Trò chơi đua xe động vật trong UNITY Engine
- ScrollSnap.cs
- Layout /
- AnimalRacing /
- Scripts /
- Assets /
- project /
2 /// Sourced from - http://forum.unity3d.com/threads/scripts-useful-4-6-scripts-collection.264161/page-2#post-1945602
3 /// Updated by ddreaper - removed dependency on a custom ScrollRect script. Now implements drag interfaces and standard Scroll Rect.
4 /// Update by xesenix - rewrote almost the entire code
5 /// - configuration for direction move instead of 2 concurrent class (easier to change direction in editor)
6 /// - supports list layout with horizontal or vertical layout need to match direction with type of layout used
7 /// - dynamic checks if scrolled list size changes and recalculates anchor positions
8 /// and item size based on itemsVisibleAtOnce and size of root container
9 /// if you don't wish to use this auto resize turn of autoLayoutItems
10 /// - fixed current page made it independent from pivot
11 /// - replaced pagination with delegate function
12 using System;
13 using UnityEngine.EventSystems;
14
15 namespace UnityEngine.UI.Extensions
16 {
17 [ExecuteInEditMode]
18 [RequireComponent(typeof(ScrollRect))]
19 [AddComponentMenu("UI/Extensions/Scroll Snap")]
20 public class ScrollSnap : MonoBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
21 {
22 // needed because of reversed behaviour of axis Y compared to X
23 // (positions of children lower in children list in horizontal directions grows when in vertical it gets smaller)
24 public enum ScrollDirection
25 {
26 Horizontal,
27 Vertical
28 }
29
30 public delegate void PageSnapChange(int page);
31
32 public event PageSnapChange onPageChange;
33
34 public ScrollDirection direction = ScrollDirection.Horizontal;
35
36 protected ScrollRect scrollRect;
37
38 protected RectTransform scrollRectTransform;
39
40 protected Transform listContainerTransform;
41
42 protected RectTransform rectTransform;
43
44 int pages;
45
46 protected int startingPage = 0;
47
48 // anchor points to lerp to to see child on certain indexes
49 protected Vector3[] pageAnchorPositions;
50
51 protected Vector3 lerpTarget;
52
53 protected bool lerp;
54
55 // item list related
56 protected float listContainerMinPosition;
57
58 protected float listContainerMaxPosition;
59
60 protected float listContainerSize;
61
62 protected RectTransform listContainerRectTransform;
63
64 protected Vector2 listContainerCachedSize;
65
66 protected float itemSize;
67
68 protected int itemsCount = 0;
69
70 [Tooltip("Button to go to the next page. (optional)")]
71 public Button nextButton;
72
73 [Tooltip("Button to go to the previous page. (optional)")]
74 public Button prevButton;
75
76 [Tooltip("Number of items visible in one page of scroll frame.")]
77 [RangeAttribute(1, 100)]
78 public int itemsVisibleAtOnce = 1;
79
80 [Tooltip("Sets minimum width of list items to 1/itemsVisibleAtOnce.")]
81 public bool autoLayoutItems = true;
82
83 [Tooltip("If you wish to update scrollbar numberOfSteps to number of active children on list.")]
84 public bool linkScrolbarSteps = false;
85
86 [Tooltip("If you wish to update scrollrect sensitivity to size of list element.")]
87 public bool linkScrolrectScrollSensitivity = false;
88
89 public Boolean useFastSwipe = true;
90
91 public int fastSwipeThreshold = 100;
92
93 // drag related
94 protected bool startDrag = true;
95
96 protected Vector3 positionOnDragStart = new Vector3();
97
98 protected int pageOnDragStart;
99
100 protected bool fastSwipeTimer = false;
101
102 protected int fastSwipeCounter = 0;
103
104 protected int fastSwipeTarget = 10;
105
106 // Use this for initialization
107 void Awake()
108 {
109 lerp = false;
110
111 scrollRect = gameObject.GetComponent<ScrollRect>();
112 scrollRectTransform = gameObject.GetComponent<RectTransform>();
113 listContainerTransform = scrollRect.content;
114 listContainerRectTransform = listContainerTransform.GetComponent<RectTransform>();
115
116 rectTransform = listContainerTransform.gameObject.GetComponent<RectTransform>();
117 UpdateListItemsSize();
118 UpdateListItemPositions();
119
120 PageChanged(CurrentPage());
121
122 if (nextButton)
123 {
124 nextButton.GetComponent<Button>().onClick.AddListener(() =>
125 {
126 NextScreen();
127 });
128 }
129
130 if (prevButton)
131 {
132 prevButton.GetComponent<Button>().onClick.AddListener(() =>
133 {
134 PreviousScreen();
135 });
136 }
137 }
138
139 void Start()
140 {
141 Awake();
142 }
143
144 public void UpdateListItemsSize()
145 {
146 float size = 0;
147 float currentSize = 0;
148 if (direction == ScrollSnap.ScrollDirection.Horizontal)
149 {
150 size = scrollRectTransform.rect.width / itemsVisibleAtOnce;
151 currentSize = listContainerRectTransform.rect.width / itemsCount;
152 }
153 else
154 {
155 size = scrollRectTransform.rect.height / itemsVisibleAtOnce;
156 currentSize = listContainerRectTransform.rect.height / itemsCount;
157 }
158
159 itemSize = size;
160
161 if (linkScrolrectScrollSensitivity)
162 {
163 scrollRect.scrollSensitivity = itemSize;
164 }
165
166 if (autoLayoutItems && currentSize != size && itemsCount > 0)
167 {
168 if (direction == ScrollSnap.ScrollDirection.Horizontal)
169 {
170 foreach (var tr in listContainerTransform)
171 {
172 GameObject child = ((Transform)tr).gameObject;
173 if (child.activeInHierarchy)
174 {
175 var childLayout = child.GetComponent<LayoutElement>();
176
177 if (childLayout == null)
178 {
179 childLayout = child.AddComponent<LayoutElement>();
180 }
181
182 childLayout.minWidth = itemSize;
183 }
184 }
185 }
186 else
187 {
188 foreach (var tr in listContainerTransform)
189 {
190 GameObject child = ((Transform)tr).gameObject;
191 if (child.activeInHierarchy)
192 {
193 var childLayout = child.GetComponent<LayoutElement>();
194
195 if (childLayout == null)
196 {
197 childLayout = child.AddComponent<LayoutElement>();
198 }
199
200 childLayout.minHeight = itemSize;
201 }
202 }
203 }
204 }
205 }
206
207 public void UpdateListItemPositions()
208 {
209 if (!listContainerRectTransform.rect.size.Equals(listContainerCachedSize))
210 {
211 // checking how many children of list are active
212 int activeCount = 0;
213
214 foreach (var tr in listContainerTransform)
215 {
216 if (((Transform)tr).gameObject.activeInHierarchy)
217 {
218 activeCount++;
219 }
220 }
221
222 // if anything changed since last check reinitialize anchors list
223 itemsCount = 0;
224 Array.Resize(ref pageAnchorPositions, activeCount);
225
226 if (activeCount > 0)
227 {
228 pages = Mathf.Max(activeCount - itemsVisibleAtOnce + 1, 1);
229
230 if (direction == ScrollDirection.Horizontal)
231 {
232 // looking for list spanning range min/max
233 scrollRect.horizontalNormalizedPosition = 0;
234 listContainerMaxPosition = listContainerTransform.localPosition.x;
235 scrollRect.horizontalNormalizedPosition = 1;
236 listContainerMinPosition = listContainerTransform.localPosition.x;
237
238 listContainerSize = listContainerMaxPosition - listContainerMinPosition;
239
240 for (var i = 0; i < pages; i++)
241 {
242 pageAnchorPositions[i] = new Vector3(
243 listContainerMaxPosition - itemSize * i,
244 listContainerTransform.localPosition.y,
245 listContainerTransform.localPosition.z
246 );
247 }
248 }
249 else
250 {
251 //Debug.Log ("-------------looking for list spanning range----------------");
252 // looking for list spanning range
253 scrollRect.verticalNormalizedPosition = 1;
254 listContainerMinPosition = listContainerTransform.localPosition.y;
255 scrollRect.verticalNormalizedPosition = 0;
256 listContainerMaxPosition = listContainerTransform.localPosition.y;
257
258 listContainerSize = listContainerMaxPosition - listContainerMinPosition;
259
260 for (var i = 0; i < pages; i++)
261 {
262 pageAnchorPositions[i] = new Vector3(
263 listContainerTransform.localPosition.x,
264 listContainerMinPosition + itemSize * i,
265 listContainerTransform.localPosition.z
266 );
267 }
268 }
269
270 UpdateScrollbar(linkScrolbarSteps);
271 startingPage = Mathf.Min(startingPage, pages);
272 ResetPage();
273 }
274
275 if (itemsCount != activeCount)
276 {
277 PageChanged(CurrentPage());
278 }
279
280 itemsCount = activeCount;
281 listContainerCachedSize.Set(listContainerRectTransform.rect.size.x, listContainerRectTransform.rect.size.y);
282 }
283
284 }
285
286 public void ResetPage()
287 {
288 if (direction == ScrollDirection.Horizontal)
289 {
290 scrollRect.horizontalNormalizedPosition = pages > 1 ? (float)startingPage / (float)(pages - 1) : 0;
291 }
292 else
293 {
294 scrollRect.verticalNormalizedPosition = pages > 1 ? (float)(pages - startingPage - 1) / (float)(pages - 1) : 0;
295 }
296 }
297
298 protected void UpdateScrollbar(bool linkSteps)
299 {
300 if (linkSteps)
301 {
302 if (direction == ScrollDirection.Horizontal)
303 {
304 if (scrollRect.horizontalScrollbar != null)
305 {
306 scrollRect.horizontalScrollbar.numberOfSteps = pages;
307 }
308 }
309 else
310 {
311 if (scrollRect.verticalScrollbar != null)
312 {
313 scrollRect.verticalScrollbar.numberOfSteps = pages;
314 }
315 }
316 }
317 else
318 {
319 if (direction == ScrollDirection.Horizontal)
320 {
321 if (scrollRect.horizontalScrollbar != null)
322 {
323 scrollRect.horizontalScrollbar.numberOfSteps = 0;
324 }
325 }
326 else
327 {
328 if (scrollRect.verticalScrollbar != null)
329 {
330 scrollRect.verticalScrollbar.numberOfSteps = 0;
331 }
332 }
333 }
334 }
335
336 void LateUpdate()
337 {
338 UpdateListItemsSize();
339 UpdateListItemPositions();
340
341 if (lerp)
342 {
343 UpdateScrollbar(false);
344
345 listContainerTransform.localPosition = Vector3.Lerp(listContainerTransform.localPosition, lerpTarget, 7.5f * Time.deltaTime);
346
347 if (Vector3.Distance(listContainerTransform.localPosition, lerpTarget) < 0.001f)
348 {
349 listContainerTransform.localPosition = lerpTarget;
350 lerp = false;
351
352 UpdateScrollbar(linkScrolbarSteps);
353 }
354
355 //change the info bullets at the bottom of the screen. Just for visual effect
356 if (Vector3.Distance(listContainerTransform.localPosition, lerpTarget) < 10f)
357 {
358 PageChanged(CurrentPage());
359 }
360 }
361
362 if (fastSwipeTimer)
363 {
364 fastSwipeCounter++;
365 }
366 }
367
368 private bool fastSwipe = false; //to determine if a fast swipe was performed
369
370
371 //Function for switching screens with buttons
372 public void NextScreen()
373 {
374 UpdateListItemPositions();
375
376 if (CurrentPage() < pages - 1)
377 {
378 lerp = true;
379 lerpTarget = pageAnchorPositions[CurrentPage() + 1];
380
381 PageChanged(CurrentPage() + 1);
382 }
383 }
384
385 //Function for switching screens with buttons
386 public void PreviousScreen()
387 {
388 UpdateListItemPositions();
389
390 if (CurrentPage() > 0)
391 {
392 lerp = true;
393 lerpTarget = pageAnchorPositions[CurrentPage() - 1];
394
395 PageChanged(CurrentPage() - 1);
396 }
397 }
398
399 //Because the CurrentScreen function is not so reliable, these are the functions used for swipes
400 private void NextScreenCommand()
401 {
402 if (pageOnDragStart < pages - 1)
403 {
404 int targetPage = Mathf.Min(pages - 1, pageOnDragStart + itemsVisibleAtOnce);
405 lerp = true;
406
407 lerpTarget = pageAnchorPositions[targetPage];
408
409 PageChanged(targetPage);
410 }
411 }
412
413 //Because the CurrentScreen function is not so reliable, these are the functions used for swipes
414 private void PrevScreenCommand()
415 {
416 if (pageOnDragStart > 0)
417 {
418 int targetPage = Mathf.Max(0, pageOnDragStart - itemsVisibleAtOnce);
419 lerp = true;
420
421 lerpTarget = pageAnchorPositions[targetPage];
422
423 PageChanged(targetPage);
424 }
425 }
426
427
428 //returns the current screen that the is seeing
429 public int CurrentPage()
430 {
431 float pos;
432
433 if (direction == ScrollDirection.Horizontal)
434 {
435 pos = listContainerMaxPosition - listContainerTransform.localPosition.x;
436 pos = Mathf.Clamp(pos, 0, listContainerSize);
437 }
438 else
439 {
440 pos = listContainerTransform.localPosition.y - listContainerMinPosition;
441 pos = Mathf.Clamp(pos, 0, listContainerSize);
442 }
443
444 float page = pos / itemSize;
445
446 return Mathf.Clamp(Mathf.RoundToInt(page), 0, pages);
447 }
448
449 public void ChangePage(int page)
450 {
451 if (0 <= page && page < pages)
452 {
453 lerp = true;
454
455 lerpTarget = pageAnchorPositions[page];
456
457 PageChanged(page);
458 }
459 }
460
461 //changes the bullets on the bottom of the page - pagination
462 private void PageChanged(int currentPage)
463 {
464 startingPage = currentPage;
465
466 if (nextButton)
467 {
468 nextButton.interactable = currentPage < pages - 1;
469 }
470
471 if (prevButton)
472 {
473 prevButton.interactable = currentPage > 0;
474 }
475
476 if (onPageChange != null)
477 {
478 onPageChange(currentPage);
479 }
480 }
481
482 #region Interfaces
483 public void OnBeginDrag(PointerEventData eventData)
484 {
485 UpdateScrollbar(false);
486
487 fastSwipeCounter = 0;
488 fastSwipeTimer = true;
489
490 positionOnDragStart = eventData.position;
491 pageOnDragStart = CurrentPage();
492 }
493
494 public void OnEndDrag(PointerEventData eventData)
495 {
496 startDrag = true;
497 float change = 0;
498
499 if (direction == ScrollDirection.Horizontal)
500 {
501 change = positionOnDragStart.x - eventData.position.x;
502 }
503 else
504 {
505 change = -positionOnDragStart.y + eventData.position.y;
506 }
507
508 if (useFastSwipe)
509 {
510 fastSwipe = false;
511 fastSwipeTimer = false;
512
513 if (fastSwipeCounter <= fastSwipeTarget)
514 {
515 if (Math.Abs(change) > fastSwipeThreshold)
516 {
517 fastSwipe = true;
518 }
519 }
520 if (fastSwipe)
521 {
522 if (change > 0)
523 {
524 NextScreenCommand();
525 }
526 else
527 {
528 PrevScreenCommand();
529 }
530 }
531 else
532 {
533 lerp = true;
534 lerpTarget = pageAnchorPositions[CurrentPage()];
535 }
536 }
537 else
538 {
539 lerp = true;
540 lerpTarget = pageAnchorPositions[CurrentPage()];
541 }
542 }
543
544 public void OnDrag(PointerEventData eventData)
545 {
546 lerp = false;
547
548 if (startDrag)
549 {
550 OnBeginDrag(eventData);
551 startDrag = false;
552 }
553 }
554 #endregion
555 }
556 }
Credit BinaryX
Sourced from - http:forum.unity3d.comthreadsscripts-useful-4-6-scripts-collection.264161page-2#post-1945602
Updated by ddreaper - removed dependency on a custom ScrollRect script. Now implements drag interfaces and standard Scroll Rect.
Update by xesenix - rewrote almost the entire code
- configuration for direction move instead of 2 concurrent class (easier to change direction in editor)
- supports list layout with horizontal or vertical layout need to match direction with type of layout used
- dynamic checks if scrolled list size changes and recalculates anchor positions
and item size based on itemsVisibleAtOnce and size of root container
if you don't wish to use this auto resize turn of autoLayoutItems
- fixed current page made it independent from pivot
- replaced pagination with delegate function
needed because of reversed behaviour of axis Y compared to X
(positions of children lower in children list in horizontal directions grows when in vertical it gets smaller)
anchor points to lerp to to see child on certain indexes
item list related
drag related
Use this for initialization
checking how many children of list are active
if anything changed since last check reinitialize anchors list
looking for list spanning range minmax
Debug.Log ("-------------looking for list spanning range----------------");
looking for list spanning range
change the info bullets at the bottom of the screen. Just for visual effect
private bool fastSwipe = false; to determine if a fast swipe was performed
Function for switching screens with buttons
Function for switching screens with buttons
Because the CurrentScreen function is not so reliable, these are the functions used for swipes
Because the CurrentScreen function is not so reliable, these are the functions used for swipes
returns the current screen that the is seeing
changes the bullets on the bottom of the page - pagination